package org.tokaf.datasearcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Vector;

import org.tokaf.MyVectorCompare;
import org.tokaf.normalizer.Normalizer;
import org.tokaf.normalizer.SimpleJenaNormalizer;
import org.tokaf.normalizer.SimpleNormalizer;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Selector;
import com.hp.hpl.jena.rdf.model.SimpleSelector;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.rdf.model.impl.PropertyImpl;
import com.hp.hpl.jena.rdf.model.impl.ResourceImpl;

/**
 * <p>Base class for all class working with Jena in memory mode - that means
 * that it loads the answer in memory and than sorts them. Its subclasses must
 * override initSource method.</p> <p>Copyright (c) 2006</p>
 * @author Alan Eckhardt
 * @version 1.0
 */
public abstract class JenaMemorySearcher extends DataSearcher {
	public JenaMemorySearcher() {
	}

	Model model;

	ArrayList results;

	int index = -1;

	protected int searchIndex = -1;

	protected int columnCount = -1;

	public JenaMemorySearcher(String db, String query, Normalizer norm) {
		initSource(db);
		initSearch(query);
		this.norm = norm;
	}

	public boolean needsSort() {
		return true;
	}

	public SimpleNormalizer getDefaultNormalizer() {
		return new SimpleJenaNormalizer();
	}
	
	public void finalize() throws Throwable {
		super.finalize();

		if (model != null)
			model.close();
	}

	public void sort(int index) {
		if (results == null)
			return;
		long startTime = System.nanoTime();
		MyVectorCompare comp = new MyVectorCompare(index, norm);
		Collections.sort(results, comp);
		initSearchTime += System.nanoTime() - startTime;
	}

	public int initSource(DataSearcher searcher) {

		long startTime = System.nanoTime();
		if (searcher instanceof JenaMemorySearcher) {
			model = ((JenaMemorySearcher) searcher).model;
			initSourceTime += System.nanoTime() - startTime;
			return 1;
		}

		if (searcher instanceof JenaSearcher) {
			model = ((JenaSearcher) searcher).model;
			initSourceTime += System.nanoTime() - startTime;
			return 1;
		}
		initSourceTime += System.nanoTime() - startTime;
		return -1;
	}

	/**
	 * advance
	 * @return int
	 */
	public int advance() {
		if (index + 1 < results.size()) {
			index++;
			return index;
		} else
			return -1;
	}

	public Object findObject(Object obj, int position, int index) {
		String queryString = "select ?x ?p ?y " + "WHERE " + "{ "
				+ obj.toString() + " " + name + " ?y . " + "} "
		// + "ORDER BY DESC(?y) "
		;
		if (index == 1) {
			return name;
		} else if (index == 2) {
			PropertyImpl p = new PropertyImpl(name);
			if (!(obj instanceof Resource))
				obj = new ResourceImpl(obj.toString());

			NodeIterator iter = model.listObjectsOfProperty((Resource) obj, p);
			if (iter.hasNext()) {
				return iter.nextNode();
			}
		}
		Query query = QueryFactory.create(queryString);
		QueryExecution qexecTemp = QueryExecutionFactory.create(query, model);
		ResultSet resultsTemp = qexecTemp.execSelect();
		if (resultsTemp.hasNext()) {
			QuerySolution solnTemp = resultsTemp.nextSolution();
			if (index == 1)
				return solnTemp.get("p");
			if (index == 2)
				return solnTemp.get("y");
			return solnTemp.get("x");
		}
		return null;
	}

	protected Object getField(int row, int column) {
		if (row < 0 || row >= results.size())
			return null;
		Vector v = (Vector) results.get(row);
		return v.get(column);
	}

	public Object getField(int column) {
		if (index < 0 || column > columnCount)
			return null;
		return getField(index, column);

	}

	public int getPosistion() {
		return index;
	}

	public void initSearch(String queryString) {
		long startTime = System.nanoTime();
		/*
		 * ResultSet results; QueryExecution qexec; QuerySolution soln; Query
		 * query = QueryFactory.create(queryString) ; qexec =
		 * QueryExecutionFactory.create(query, model) ; results =
		 * qexec.execSelect() ; columnCount=results.getResultVars().size();
		 */
		columnCount = 3;
		results = new ArrayList();

		PropertyImpl p = new PropertyImpl(name);
		Selector select = new SimpleSelector((Resource) null, p, (Literal) null);

		StmtIterator iter = model.listStatements(select);
		while (iter.hasNext()) {
			Statement stat = (Statement) iter.nextStatement();
			Vector v = new Vector();
			v.add(stat.getSubject());
			v.add(name);
			v.add(stat.getObject());
			results.add(v);
			// s=stat.asTriple().getObject().getName();
			/*
			 * for(int i=0;i<columnCount;i++) v.add(iter.);
			 */
			;
		}
		// MyVectorCompare comp = new MyVectorCompare(2, norm);
		// Collections.sort(solution, comp);

		index = 0;
		/*
		 * while (results.hasNext()) { soln = results.nextSolution() ; Vector
		 * v=new Vector(); for(int i=0;i<columnCount;i++)
		 * v.add(soln.get(results.getResultVars().get(i).toString()));
		 * solution.add(v); } index=0; if(qexec!=null) qexec.close();
		 */
		initSearchTime += System.nanoTime() - startTime;
	}

	public boolean hasNext() {
		if (results == null || index == -1 || index >= results.size())
			return false;
		return true;
	}

	/**
	 * initSource
	 * @param db String
	 * @return int
	 */
	public abstract int initSource(String db);

	public Object getFieldAtPosition(int index, int position) {
		return getField(index, position);
	}

	public Object next() {
		if (index < 0 || index >= results.size())
			throw new NoSuchElementException();
		Vector v = (Vector) results.get(index);
		index++;
		return v;
	}

	public void resetSearch() {
		if (index != -1)
			index = 0;
	}
}
